﻿using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json;
using Nito.AsyncEx;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Crgd.UAuthServer.Sdk
{
    public class AppAuthServer : IAsyncDisposable
    {
        public AppAuthServer(IOptions<UAuthAppOptions> options)
        {
            this.Options = options.Value;
            this.httpClient = new HttpClient();
            this.httpClient.BaseAddress = new Uri(options.Value.AuthServerUrl);
        }

        public UAuthAppOptions Options { get; }

        private readonly HttpClient httpClient;

        public bool IsAuthenticationed
        {
            get; private set;
        }

        public string accessToken { get; set; }
        public string refreshToken { get; set; }

        private readonly AsyncLock _mutex = new AsyncLock();

        public async Task<T> RequestAsync<T>(HttpMethod method, string url, object data = null)
        {
            // 异步锁避免并发导致多次登录
            using  (await _mutex.LockAsync())
            {
                // 如果未登录，先登录
                if (!this.IsAuthenticationed)
                {
                    await this.AuthenticationAsync();
                }
            }
            var request = new HttpRequestMessage(method, url);
            if (data != null)
            {
                request.Content = JsonContent.Create(data);
            }
            if (this.IsAuthenticationed)
            {
                request.Headers.Add(HeaderNames.Authorization, "Bearer " + this.accessToken);
                request.Headers.Add("X-Authorization", "Bearer " + this.refreshToken);
            }

            var response = await this.httpClient.SendAsync(request);

            if (response.Headers.Contains("access-token") && response.Headers.Contains("access-token").ToString() != "invalid_token")
            {
                this.accessToken = response.Headers.Contains("access-token").ToString();
                this.IsAuthenticationed = true;
            }
            if (response.Headers.Contains("x-access-token"))
            {
                this.accessToken = response.Headers.Contains("x-access-token").ToString();
            }

            var result = await response.Content.ReadFromJsonAsync<XnRestfulResult<T>>();
            if (!result.Success)
            {
                var error = new Exception(result.Message.ToString());
                error.Data.Add("Response", result);
                throw error;
            }
            return result.Data;
        }

        /// <summary>
        /// 当前应用登录到AuthServer
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="appKey"></param>
        /// <returns></returns>
        protected async Task AuthenticationAsync()
        {
            try
            {
                await this.RequestAsync<string>(HttpMethod.Post, "GetAccessToken", new
                {
                    appKey = this.Options.AppKey,
                    appSecret = this.Options.AppSecret
                });
                this.IsAuthenticationed = true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 从AuthServer登出
        /// </summary>
        /// <returns></returns>
        protected async Task DeuthenticationAsync()
        {
            using (await _mutex.LockAsync())
            {
                this.accessToken = null;
                this.refreshToken = null;
                this.IsAuthenticationed = false;
            }
        }

        /// <summary>
        /// 验证登录身份
        /// </summary>
        /// <param name="sessionKey"></param>
        /// <returns></returns>
        public async Task<UAuthIdentity> VerifyIdentityAsync(string sessionKey)
        {
            var user = await this.RequestAsync<UAuthIdentity>(HttpMethod.Get, $"GetIdentityBySessionKey?session_key={sessionKey}");
            return user;
        }

        /// <summary>
        /// 获取权限信息，用户及客户端APP共用此方法
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<IPermission> GetPermissionsAsync(string identity)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 获取身份验证登录到目标应用时使用的SessionKey
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="appSecret"></param>
        /// <param name="tenantId"></param>
        /// <returns></returns>
        public async Task<string> GetSessionKeyAsync(string appId, string tenantId)
        {
            return await this.RequestAsync<string>(HttpMethod.Get, $"GetSerssionKey?appId={appId}&tenantId={tenantId}");
        }

        public async ValueTask DisposeAsync()
        {
            await this.DeuthenticationAsync();
        }
    }
}
